﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Collections.Concurrent;

namespace Core
{
    public interface ISession
    {
        uint SessionID { get; }
        EntityObject Entity { get; }
        IPEndPoint IPEndPoint { get; }
        void SendMessage(IMessage message);
        ETTask<Response> RpcMessage<Response>(IRequestMessage message)
            where Response : IResponseMessage;
        bool Register(uint sessionID);
        void LinkSession(ISession session);
        void UnlinkSession(ISession session);
        List<ISession> GetLinkSessions();
        void Disconnect();
    }

    internal abstract class Session : ISession
    {
        public uint SessionID { get; set; }
        public EntityObject Entity { get; set; }
        public IPEndPoint IPEndPoint { get; set; }

        public bool IsProcessing { get { return rpcTasks.Count > 0; } }

        public byte rpcID;
        public Dictionary<byte, ETTask<IMessage>> rpcTasks = new Dictionary<byte, ETTask<IMessage>>();

        public HashSet<uint> linkSessionIDs = new HashSet<uint>();

        public abstract void SendMessage(IMessage message);
        public abstract void SendMessage(IMessage message, byte rpcID);
        public abstract bool Register(uint sessionID);
        public abstract void Disconnect();

        public byte GetNextRpcID()
        {
            if (rpcID >= Config.RPC_ID_MASK)
                rpcID = 0;
            rpcID++;
            return rpcID;
        }

        public async ETTask<Response> RpcMessage<Response>(IRequestMessage message)
            where Response : IResponseMessage
        {
            var currentRpcID = GetNextRpcID();
            if (rpcTasks.ContainsKey(currentRpcID))
                throw new Exception($"rpc:{currentRpcID}消息已存在，无法发送");

            SendMessage(message, currentRpcID);

            var task = ETTask<IMessage>.Create(true);
            rpcTasks[currentRpcID] = task;

            return (Response)await task;
        }

        public void LinkSession(ISession session)
        {
            linkSessionIDs.Add(session.SessionID);
            ((Session)session).linkSessionIDs.Add(SessionID);
            new CoreTip($"连接会话:{SessionID}<-->{session.SessionID}").Publish();
        }

        public void UnlinkSession(ISession session)
        {
            linkSessionIDs.Remove(session.SessionID);
            ((Session)session).linkSessionIDs.Remove(SessionID);
            new CoreTip($"断开会话:{SessionID}<-->{session.SessionID}").Publish();
        }

        public List<ISession> GetLinkSessions()
        {
            var list = new List<ISession>();

            foreach (var id in linkSessionIDs)
            {
                var linkSession = new GetSession(id).Publish().session;
                if (linkSession != null)
                    list.Add(linkSession);
            }

            return list;
        }

        public virtual void Dispose()
        {
            rpcID = 0;
            Entity.Destroy();
            rpcTasks.Clear();
        }
    }
}
